﻿using System.Dynamic;
using Basic.FormCollect;
using Basic.FormExtendService;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.PageCalculate.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using Basic.UserFormService.Page.Interface;
using WeDonekRpc.Helper;
using WeDonekRpc.SqlSugar;
using WeDonekRpc.SqlSugar.VirtualQuery;

namespace Basic.UserFormService.Page
{
    internal class CensusTableCalculate : ICensusTableCalculate
    {
        private readonly IPageCensusTableService _TableBody;
        private readonly IAgentFormCollect _AgentForm;
        private readonly IEmpService _Emp;
        private readonly ICompanyService _Company;
        private readonly IUnitDeptService _UnitDept;
        private readonly IDictItemService _DictItem;
        private readonly ITreeDicService _TreeDic;

        public CensusTableCalculate ( IPageCensusTableService table,
            IAgentFormCollect agentForm,
            IEmpService emp,
            ICompanyService company,
            IUnitDeptService unitDept,
            IDictItemService dictItem,
            ITreeDicService treeDic )
        {
            this._TableBody = table;
            this._AgentForm = agentForm;
            this._Emp = emp;
            this._Company = company;
            this._UnitDept = unitDept;
            this._DictItem = dictItem;
            this._TreeDic = treeDic;
        }

        public CensusTableResult Calculate ( CalculateArg arg )
        {
            CensusTableBody body = this._TableBody.Get(arg.Id, arg.CompanyId, arg.Extend);
            if ( body.Query == null )
            {
                return null;
            }
            QueryStruct query;
            if ( !arg.Search.IsNull() )
            {
                IWhereCol[] where = arg.Search.GetWhere(body.Cols);
                query = body.Query.Clone();
                query.Where = query.Where.Merge(where);
            }
            else
            {
                query = body.Query;
            }
            ExpandoObject[] rows = this._AgentForm.Gets(query);
            if ( rows.IsNull() )
            {
                return null;
            }
            CensusTableResult result = new CensusTableResult();
            result.Column = this._Format(rows, body, out ExpandoObject[] datas);
            result.Rows = datas;
            result.MergeCol = body.MergeCol;
            result.Cols = body.CensusCol.ConvertAll(c =>
            {
                CensusColSet cols = new CensusColSet
                {
                    Name = c.Name,
                    DataType = c.DataType,
                    FuncType = c.FuncType,
                    ColSet = c.ColSet
                };
                if ( c.FuncType != FormColumnFuncType.无 )
                {
                    cols.Texts = this._LoadLabel(c, rows);
                }
                return cols;
            });
            return result;
        }
        private PageTableCol[] _Format ( ExpandoObject[] sour, CensusTableBody body, out ExpandoObject[] rows )
        {
            if ( body.RowTrunCol == null )
            {
                rows = sour;
                return body.Columns.ConvertAll(this._FormatCol);
            }
            IDictionary<string, object>[] vals = sour;
            Dictionary<string, ExpandoObject> results = new Dictionary<string, ExpandoObject>();
            string[] keys = body.RowTrunCol.GroupBy;
            string[] codes = vals.Convert(a =>
            {
                string key = string.Join('_', keys.ConvertAll(c => a[c]));
                a.Add("TKey", key);
                if ( !results.ContainsKey(key) )
                {
                    IDictionary<string, object> row = new ExpandoObject();
                    keys.ForEach(c => row[c] = a[c]);
                    results.Add(key, (ExpandoObject)row);
                }
                if ( a.TryGetValue(body.RowTrunCol.Name, out object val) && val != null )
                {
                    return Convert.ToString(val);
                }
                return null;
            });
            List<PageTableCol> cols = new List<PageTableCol>();
            PageColTemplate trunCol = null;
            body.Columns.ForEach(a =>
            {
                if ( a.IsRowTrun )
                {
                    Dictionary<string, string> items = this._GetItems(body.RowTrunCol, codes);
                    items.ForEach(( key, name ) =>
                    {
                        PageTableCol t = new PageTableCol
                        {
                            Key = key,
                            Label = name
                        };
                        t.Children = a.Children.ConvertAll(c => new PageTableCol
                        {
                            Align = c.Align,
                            Key = key + "_" + c.Name,
                            Label = c.Label,
                            Width = c.MinWidth
                        });
                        cols.Add(t);
                    });
                    trunCol = a;
                }
                else
                {
                    cols.Add(new PageTableCol
                    {
                        Align = a.Align,
                        Key = a.Name,
                        Label = a.Label,
                        Width = a.MinWidth
                    });
                }
            });

            vals.ForEach(c =>
            {
                string key = (string)c["TKey"];
                string code = (string)c[body.RowTrunCol.Name];
                IDictionary<string, object> row = results[key];
                trunCol.Children.ForEach(a =>
                {
                    row[code + "_" + a.Name] = c[a.Name];
                });
            });
            rows = results.Values.ToArray();
            return cols.ToArray();
        }
        private Dictionary<string, string> _GetItems ( PageRowTrunCol col, string[] codes )
        {
            if ( col.FuncType == FormColumnFuncType.选项值 )
            {
                return codes.ToDictionary(c => c, a => col.Items[a]);
            }
            else if ( col.FuncType == FormColumnFuncType.字典项 )
            {
                return this._DictItem.GetNames(col.DicId.Value, codes);
            }
            else
            {
                return this._TreeDic.GetNames(col.DicId.Value, codes);
            }
        }
        private PageTableCol _FormatCol ( PageColTemplate col )
        {
            PageTableCol t = new PageTableCol
            {
                Align = col.Align,
                Key = col.Name,
                Label = col.Label,
                Width = col.MinWidth
            };
            if ( !col.Children.IsNull() )
            {
                t.Children = col.Children.ConvertAll(this._FormatCol);
            }
            return t;
        }
        private Dictionary<string, string> _LoadLabel ( PageCensusColumn col, IDictionary<string, object>[] rows )
        {
            if ( col.FuncType == FormColumnFuncType.人员ID )
            {
                long[] empId = rows.Distinct(a =>
                {
                    return Convert.ToInt64(a[col.Name]);
                });
                return this._Emp.GetEmpName(empId).ToDictionary(a => a.Key.ToString(), a => a.Value);
            }
            else if ( col.FuncType == FormColumnFuncType.公司ID )
            {
                long[] comId = rows.Distinct(a =>
                {
                    return Convert.ToInt64(a[col.Name]);
                });
                return this._Company.GetNames(comId).ToDictionary(a => a.Key.ToString(), a => a.Value);
            }
            else if ( col.FuncType == FormColumnFuncType.部门单位ID )
            {
                long[] deptId = rows.Distinct(a =>
                {
                    return Convert.ToInt64(a[col.Name]);
                });
                return this._UnitDept.GetNames(deptId).ToDictionary(a => a.Key.ToString(), a => a.Value);
            }
            else if ( col.FuncType == FormColumnFuncType.选项值 )
            {
                return col.Items;
            }
            else if ( col.FuncType == FormColumnFuncType.树形字典 )
            {
                string[] codes = rows.Distinct(a =>
                {
                    return a[col.Name].ToString();
                });
                return this._TreeDic.GetNames(col.DicId.Value, codes);
            }
            else
            {
                string[] codes = rows.Distinct(a =>
                {
                    return a[col.Name].ToString();
                });
                return this._DictItem.GetNames(col.DicId.Value, codes);
            }
        }
    }
}
